package mmc.resource;

import static org.lwjgl.opengl.GL11.GL_NEAREST;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_MAG_FILTER;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_MIN_FILTER;
import static org.lwjgl.opengl.GL11.glBindTexture;
import static org.lwjgl.opengl.GL11.glGenTextures;
import static org.lwjgl.opengl.GL11.glTexImage2D;
import static org.lwjgl.opengl.GL11.glTexParameteri;

import java.awt.image.BufferedImage;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Map;
import java.util.TreeMap;

import javax.imageio.ImageIO;

import mmc.Constants;

import org.lwjgl.opengl.GL11;

public class TextureLoader {
	
	private static final Map<String, Texture> TEXTURE_CACHE = new TreeMap<String, Texture>();
	
	public static Texture load(String url){
		if(Constants.IS_SERVER){//server does not need textures
			new RuntimeException("WARNING: Server tried to load texture "+url).printStackTrace();
			return null;
		}
		
		Texture tex = TEXTURE_CACHE.get(url);
		if(tex!=null)
			return tex;
		
		try {
			tex = new TextureLoaderTexture(ImageIO.read(ClassLoader.getSystemResourceAsStream(url)));
			System.out.println("loading texture "+url);
			TEXTURE_CACHE.put(url, tex);
			return tex;
		} catch (Exception e) {
			throw new RuntimeException("Exception while loading Texture: "+e.getMessage(),e);
		}
	}
	
	public static Texture load(String name, BufferedImage img){
		if(Constants.IS_SERVER){//server does not need textures
			new RuntimeException("WARNING: Server tried to load texture "+name).printStackTrace();
			return null;
		}
		
		Texture tex = TEXTURE_CACHE.get(name);
		if(tex!=null){
			new RuntimeException("Warning: caller generated same Texture twice!").printStackTrace();
			return tex;
		}
		
		tex = new TextureLoaderTexture(img);
		System.out.println("loading texture "+name);
		TEXTURE_CACHE.put(name, tex);
		return tex;
	}
	
	static class TextureLoaderTexture extends Texture{

		private TextureLoaderTexture(BufferedImage img) {
			super(glGenTextures());
			
			int len = img.getWidth()*img.getHeight();
			
			ByteBuffer buffer = ByteBuffer.allocateDirect(len * 4); //RGBA
			buffer.order(ByteOrder.nativeOrder());
			
			for(int j=0;j<img.getHeight();j++){
				for(int i=0;i<img.getWidth();i++){
					int k = img.getRGB(i, j);
					buffer.put(getByte(k,2)); //R
					buffer.put(getByte(k,1)); //G
					buffer.put(getByte(k,0)); //B
					buffer.put(getByte(k,3)); //A
				}
			}
			buffer.flip();
			
			glBindTexture(GL_TEXTURE_2D,id);
			glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
			glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
			glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, img.getWidth(), img.getHeight(), 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer);
		}
		
		private byte getByte(int i, int byteNr){
			return (byte)((i>>byteNr*8)&255);
		}
	}
	
	public static void clearTextureCache(){
		TEXTURE_CACHE.clear();
	}
}
